package com.gitee.feizns.quickstart.graalvm;

import com.gitee.feizns.dynamic.io.Ios;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.HostAccess;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.ByteSequence;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;

/**
 * js 上下文
 * @author feizns
 * @since 2025/4/25
 */
@Getter
@RequiredArgsConstructor
public class Polyglot implements AutoCloseable {

    /**
     * 语言编号
     */
    private final String languageId;

    /**
     * 上下文
     */
    private final Context context;

    /**
     * {@link Context#eval(String, CharSequence)}
     * @param script 脚本
     * @return {@link Value }
     */
    public Value eval(CharSequence script) {
        return context.eval(languageId, script);
    }
    
    /**
     * {@link Context#eval(Source)}
     * @param source 源
     * @return {@link Value }
     */
    public Value eval(Source source) {
        return context.eval(source);
    }

    /**
     * 加载脚本代码
     * @param url 网址
     * @return {@link Object}
     */
    @SneakyThrows
    public Value eval(URL url) {
        return eval(Source.newBuilder(languageId, url).build());
    }

    /**
     * 加载脚本代码
     * @param file 文件
     * @return {@link Object}
     */
    @SneakyThrows
    public Value eval(File file) {
        return eval(Source.newBuilder(languageId, file).build());
    }

    /**
     * 加载脚本代码
     * @param byteSequence 字节序列
     * @param name 名字
     * @return {@link Object}
     */
    @SneakyThrows
    public Value eval(ByteSequence byteSequence, String name) {
        return eval(Source.newBuilder(languageId, byteSequence, name).build());
    }

    /**
     * 加载脚本代码
     * @param byteSequence 字节序列
     * @return {@link Value }
     */
    @SneakyThrows
    public Value eval(ByteSequence byteSequence) {
        return eval(Source.newBuilder(languageId, byteSequence, null).build());
    }

    /**
     * 加载脚本代码
     * @param is {@link InputStream}
     * @param name 名字
     * @return {@link Object}
     */
    @SneakyThrows
    public Value eval(InputStream is, String name) {
        return eval(Source.newBuilder(languageId, ByteSequence.create(Ios.asBytes(is)), name).build());
    }

    /**
     * 加载脚本代码
     * @param is {@link InputStream}
     * @return {@link Value }
     */
    @SneakyThrows
    public Value eval(InputStream is) {
        return eval(Source.newBuilder(languageId, ByteSequence.create(Ios.asBytes(is)), null).build());
    }

    /**
     * 获取绑定
     * @return {@link Value }
     */
    public Value getBindings() {
        return context.getBindings(languageId);
    }

    /**
     * 放置成员
     * @param identifier 标识符
     * @param value 值
     */
    public Polyglot putMember(String identifier, Object value) {
        context.getBindings(languageId).putMember(identifier, value);
        return this;
    }

    /**
     * 全部放
     * @param variables 变量
     * @return {@link Polyglot }
     */
    public Polyglot putAll(Map<String, Object> variables) {
        variables.forEach(this::putMember);
        return this;
    }

    /**
     * 构建执行上下文
     * @param languageId 语言编号
     * @param context 上下文
     * @return {@link Polyglot }
     */
    public static Polyglot build(String languageId, Context context) {
        return new Polyglot(languageId, context);
    }

    /**
     * 构建js执行上下文
     * @param context 上下文
     * @return {@link Polyglot }
     */
    public static Polyglot js(Context context) {
        return new Polyglot("js", context);
    }

    /**
     * 构建js执行上下文
     * @return {@link Polyglot }
     */
    public static Polyglot js() {
        return js(Context.newBuilder("js").allowHostAccess(HostAccess.ALL).build());
    }

    /**
     * 构建python执行上下文
     * @param context 上下文
     * @return {@link Polyglot }
     */
    public static Polyglot python(Context context) {
        return new Polyglot("python", context);
    }

    /**
     * 构建python执行上下文
     * @return {@link Polyglot }
     */
    public static Polyglot python() {
        return python(Context.newBuilder("python").allowHostAccess(HostAccess.ALL).build());
    }

    @Override
    public void close() {
        context.close();
    }

}
